﻿using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Main : MonoBehaviour
{
    public GameObject[] prefabs;//用于存放所有的水果类型的数组
    public GameObject[,] objects;//用于存放游戏运行时所有实例化的水果
    public GameObject[] effects;
    public int Column;//列
    public int Row;//行
    public float TBsize = 1;//图标的大小
    public float starTime = 1;
    public Text text;
    public int Score;
    List<GameObject> cache = new List<GameObject>();
    // Start is called before the first frame update
    void Start()
    {
        objects = new GameObject[Column, Row];
        int max = prefabs.Length;//用于记录有多少个水果类型（水果类型数组的长度）
        float sx = Column * -0.5f * TBsize/*列的初始位置位置*/ + TBsize * 0.5f/*间隙*/;
        float sy = Row * -0.5f * TBsize + TBsize * 0.5f;//初始行位置
        for (int i=0;i<Column;i++)//列
        {
            for(int j=0;j<Row;j++)//行
            {
                int index = Random.Range(0,max);//随机获取水果
                GameObject go = GameObject.Instantiate(prefabs[index]);//随机获取水果下标之和实例化出来
                go.transform.SetParent(transform);//给实例化出来的水果建一个父对象，这个父对象是代码所挂载的对象（transform）
                go.transform.localPosition = new Vector3(i* TBsize + sx,j* TBsize + sy,0);//transform.localPosition相对于父变换的变换位置。
                go.transform.localScale = new Vector3(TBsize, TBsize, TBsize);//相对于父对象的变换缩放。
                Mark mark=go.AddComponent<Mark>(); //将名为 Mark 的 组件类 添加到该游戏对象。
                mark.Column = i;//水果所在的列
                mark.Row = j;//水果所在的行
                mark.Index = index;//是什么水果
                go.name = index.ToString();
                go.AddComponent<BoxCollider2D>();
                objects[i, j] = go;
                global::UnityEngine.Debug.Log($"{nameof(Main)}:11111 ");
            }
        } 
    }
    // Update is called once per frame
    void Update()
    {
        if(starTime>0)
        {
            starTime -= Time.deltaTime;
        }
        if(starTime<0)
        {
            if(Input.GetMouseButtonDown(0))//获取鼠标左键
            {
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction);
                if(hit.transform!=null)
                {
                    lasCol = curCol;
                    lasRow = curRow;
                    Mark mark = hit.transform.GetComponent<Mark>();
                    curCol = mark.Column;
                    curRow = mark.Row;
                    cache.Clear();//清空
                    Check(hit.transform.gameObject.name,mark.Column,mark.Row);
                    if(cache.Count>=3)//当上下左右同样的水果超过三个或三个以上时就消除
                    {
                        AddScore(cache.Count);
                        PlayDestory(); 
                    }
                    else
                    {
                        cache.Clear();
                        Swap();
                    }
                }
            }
        }
    }
    void Check(string type,int column,int row)//判断上下左右的水果是否有一样的，如果有则记录水果的位置给它缓存起来
    {
        if (row < 0 || row >= Row || column < 0 || column >= Column)
            return;
        GameObject go = objects[column,row];
        if (go == null)
            return;
        if (go.name != type)
            return;
        if (cache.Contains(go))//防止重复添加
            return;
        cache.Add(go);
        Check(type, column, row - 1);
        Check(type, column, row + 1);
        Check(type, column-1, row);
        Check(type, column+1, row);
    }
    void PlayDestory()//消除水果
    {
        float sx = Column * -0.5f * TBsize/*列的初始位置位置*/ + TBsize * 0.5f/*间隙*/;
        float sy = Row * -0.5f * TBsize + TBsize * 0.5f;//初始行位置
        for (int i=0;i<cache.Count;i++)
        {
            Mark mark = cache[i].GetComponent<Mark>();
            objects[mark.Column, mark.Row]=null;
            GameObject go = GameObject.Instantiate(effects[mark.Index]);
            go.transform.SetParent(transform);
            go.transform.position = new Vector3(mark.Column * TBsize + sx, mark.Row * TBsize+sy,0);
            go.transform.localScale = new Vector3(TBsize, TBsize, TBsize);
            GameObject.Destroy(cache[i]);
        }
        StartCoroutine(Wait(0.6f,Fall));
        Fall();
    }
    IEnumerator Wait(float time,System.Action action)
    {
        yield return new WaitForSeconds(time);
        action();
    }
    void Fall()//消除后 上面的水果掉落下来
    {
        float sx = Column * -0.5f * TBsize/*列的初始位置位置*/ + TBsize * 0.5f/*间隙*/;
        float sy = Row * -0.5f * TBsize + TBsize * 0.5f;//初始行位置
        for(int i=0;i<Column;i++)
        {
            int count = 0;
            for(int j=0;j<Row;j++)
            {
                if(objects[i,j]==null)
                {
                    count++;
                }
                else
                {
                    if(count>0)
                    {
                        Mark m = objects[i, j].GetComponent<Mark>();
                        int row = j - count;
                        m.Row = row;
                        objects[i, row] = objects[i, j];
                        objects[i, row].transform.DOMove(new Vector3(i * TBsize + sx, row * TBsize + sy,0),0.3f);
                        objects[i,j]= null;
                    }
                }
            }
        }
        Add();//掉落后就添加
    }
    void Add()//掉落下来后空的地方添加新的水果
    {
        float sx = Column * -0.5f * TBsize/*列的初始位置位置*/ + TBsize * 0.5f/*间隙*/;
        float sy = Row * -0.5f * TBsize + TBsize * 0.5f;//初始行位置
        for(int i=0;i<Column;i++)
        {
            for(int j=0;j<Row;j++)
            {
                if(objects[i,j]==null)
                {
                    int max = prefabs.Length;
                    int index = Random.Range(0, max);
                    GameObject go = GameObject.Instantiate(prefabs[index]);//随机获取水果下标之和实例化出来
                    go.transform.SetParent(transform);//给实例化出来的水果建一个父对象，这个父对象是代码所挂载的对象（transform）
                    go.transform.localPosition = new Vector3(i * TBsize + sx, (Row+1) * TBsize + sy, 0);//transform.localPosition相对于父变换的变换位置。
                    go.transform.DOMove(new Vector3(i * TBsize + sx, j * TBsize + sy, 0),0.3f);//新实例化的水果向下掉落，掉落速度为0.3秒
                    go.transform.localScale = new Vector3(TBsize, TBsize, TBsize);//相对于父对象的变换缩放。
                    Mark mark = go.AddComponent<Mark>(); //将名为 Mark 的 组件类 添加到该游戏对象。
                    mark.Column = i;//水果所在的列
                    mark.Row = j;//水果所在的行
                    mark.Index = index;//是什么水果
                    go.name = index.ToString();
                    go.AddComponent<BoxCollider2D>();
                    objects[i, j] = go;
                }
            }
        }
    }
    int curCol, curRow;//当前选择的列和行
    int lasCol, lasRow;//上一次选择的列和行
    void Swap()
    {
        int ox = curCol - lasCol;//当前选择的列和上一次选择的列的位置差
        int oy = curRow - lasRow;//当前选择的行和上一次选择的行的位置差
        if (oy==0)//判断选择的是不是行
        {
            if(ox==1||ox==-1)//判断你要交换的两个水果位之差是否相邻
            {
                SwapTest();
            }
        }
        else if(ox==0)//判断选择的是不是列
        {
            if(oy==1||oy==-1)//判断你要交换的两个水果位之差是否相邻
            {
                SwapTest();
            }
        }
    }
    void SwapTest()//交换
    {
        bool fail = true;
        GameObject a = objects[curCol, curRow];
        GameObject b = objects[lasCol, lasRow];
        objects[curCol, curRow] = b;
        objects[lasCol, lasRow] = a;
        var bqa = b.GetComponent<Mark>();
        bqa.Column = curCol;
        bqa.Row = curRow;
        var bqb = b.GetComponent<Mark>();
        bqb.Column = lasCol;
        bqb.Row = lasRow;
        //定义局部变量记录用户当前选择的行列和上一次选择的行列（1.2.3.4），防止用户再次单机造成的记录改变
        int cc = curCol;//1
        int cr = curRow;//2
        int lc = lasCol;//3
        int lr = lasRow;//4
        a.transform.DOKill();
        a.transform.DOMove(b.transform.position, 0.3f);//位置交换动作
        b.transform.DOKill();
        b.transform.DOMove(a.transform.position, 0.3f).onComplete = () =>
        {
            cache.Clear();
            Check(b.name, cc, cr);
            int c = 0;
            if(cache.Count>=3)
            {
                c += cache.Count;
                fail = false;
                PlayDestory();
            }
            cache.Clear();
            Check(a.name, lc, lr);
            if(cache.Count>=3)
            {
                c += cache.Count;
                fail = false;
                PlayDestory();
            }
            cache.Clear();
            AddScore(c);
            if(fail)
            {
                objects[cc, cr] = a;
                objects[lc, lr] = b;
                a.transform.DOMove(b.transform.position, 0.3f);
                b.transform.DOMove(a.transform.position, 0.3f);
                bqa.Column = cc;
                bqa.Row = cr;
                bqb.Column = lc;
                bqb.Row = lr;
            }
        };
    }
    void AddScore(int count)//添加分数
    {
        if (count < 3)
            return;
        Score += count * 100;
        count -= 3;
        Score += count * count * 10;
        text.text = Score.ToString();
    }
}
